package org.university.auth;

import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTException;
import cn.hutool.jwt.JWTUtil;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.*;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import org.university.config.JwtConfig;
import org.university.service.CustomUserDetailsService;
import org.university.util.JwtUtils;

import java.io.IOException;

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private final static Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);

    private static final String[] WHITE_LIST = {
            "/api/auth/login",
            "/api/auth/register/student",
            "/api/auth/register/teacher",
            "/api/auth/change-password"
    };

    @Resource
    private JwtUtils jwtUtils;

    @Resource
    private CustomUserDetailsService userDetailsService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        // 处理 OPTIONS 请求
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpStatus.OK.value());
            filterChain.doFilter(request, response);
            return;
        }

        // 检查白名单
        String requestURI = request.getRequestURI();
        for (String url : WHITE_LIST) {
            if (requestURI.startsWith(url)) {
                filterChain.doFilter(request, response);
                return;
            }
        }

        try {
            String token = extractToken(request);

            if (token == null) {
                logger.error("请求头中未找到token");
                sendErrorResponse(response, HttpStatus.UNAUTHORIZED, "未提供认证令牌");
                return;
            }

            if (!jwtUtils.verifyToken(token)) {
                logger.error("token验证失败");
                sendErrorResponse(response, HttpStatus.UNAUTHORIZED, "无效的认证令牌");
                return;
            }

            final JWT jwt = JWTUtil.parseToken(token);
            String userId = jwtUtils.getUserId(jwt);

            // 清除之前的认证信息
            SecurityContextHolder.clearContext();

            // 加载用户详情并检查状态
            UserDetails userDetails;
            try {
                userDetails = userDetailsService.loadUserByUsername(userId);

                // 检查用户状态
                if (!userDetails.isEnabled()) {
                    throw new DisabledException("用户已被禁用");
                }
                if (!userDetails.isAccountNonLocked()) {
                    throw new LockedException("用户账号已被锁定");
                }
                if (!userDetails.isAccountNonExpired()) {
                    throw new AccountExpiredException("用户账号已过期");
                }
                if (!userDetails.isCredentialsNonExpired()) {
                    throw new CredentialsExpiredException("用户凭证已过期");
                }
            } catch (UsernameNotFoundException e) {
                logger.error("用户不存在: {}", userId);
                sendErrorResponse(response, HttpStatus.UNAUTHORIZED, "用户不存在");
                return;
            } catch (AuthenticationException e) {
                logger.error("用户状态异常: {}", e.getMessage());
                sendErrorResponse(response, HttpStatus.UNAUTHORIZED, e.getMessage());
                return;
            }

            // 创建认证对象
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                    userDetails, null, userDetails.getAuthorities()
            );
            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

            // 设置安全上下文
            SecurityContext context = SecurityContextHolder.createEmptyContext();
            context.setAuthentication(authentication);
            SecurityContextHolder.setContext(context);

            request.setAttribute("currentUserId", userId);

        } catch (JWTException e) {
            logger.error("Token解析失败", e);
            SecurityContextHolder.clearContext();
            sendErrorResponse(response, HttpStatus.UNAUTHORIZED, "Token解析失败");
            return;
        } catch (Exception e) {
            logger.error("认证过程异常", e);
            SecurityContextHolder.clearContext();
            sendErrorResponse(response, HttpStatus.INTERNAL_SERVER_ERROR, "认证服务异常");
            return;
        }

        filterChain.doFilter(request, response);
    }

    private String extractToken(HttpServletRequest request) {
        String bearerToken = request.getHeader(JwtConfig.TOKEN_HEADER);
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }

    private void sendErrorResponse(HttpServletResponse response, HttpStatus status, String message) throws IOException {
        response.setStatus(status.value());
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(String.format("{\"code\": %d, \"message\": \"%s\"}", status.value(), message));
    }
}